package com.fram.common.util.alipay;

import java.math.BigDecimal;
import java.util.Date;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alipay.easysdk.factory.Factory;
import com.alipay.easysdk.factory.Factory.Payment;
import com.alipay.easysdk.kernel.Config;
import com.alipay.easysdk.kernel.util.ResponseChecker;
import com.alipay.easysdk.payment.app.models.AlipayTradeAppPayResponse;
import com.alipay.easysdk.payment.common.models.AlipayTradeRefundResponse;
import com.fram.common.canstant.ErrCode;
import com.fram.common.exception.ProAffairException;
import com.fram.common.exception.ProRunTimeException;
import com.fram.common.util.date.DateUtils;
import com.fram.common.util.json.JSONTools;
import com.fram.entity.SysPayment;

/**
 * @作者： 陳曉鬆 @时间： 2020年8月11日 - 上午9:25:09 @description：->
 */
public class AlipayUtils {

	private static Logger LOG = LoggerFactory.getLogger(AlipayUtils.class);

	/**
	 * @作者：陳曉鬆 @时间：2020年8月11日 上午9:31:37 @版本：V1.0 @description：-> app支付
	 */
	public static String appPay(SysPayment payment, String subject, String outTradeNo, String totalAmount, Date invalidTime) throws ProAffairException {
		if (payment == null) {
			throw new ProRunTimeException(ErrCode.ERR_PARAMETER.getReturnCode(), ErrCode.ERR_PARAMETER.getReturnMsg() + ":支付信息不存在");
		}
		Long time = invalidTime.getTime() - System.currentTimeMillis();
		if (time <= 0) {
			throw new ProRunTimeException(ErrCode.ERR_PARAMETER.getReturnCode(), "订单支付信息已经过期");
		}
		// 1. 设置参数（全局只需设置一次）
		Factory.setOptions(getOptions(payment));
		try {
			AlipayTradeAppPayResponse response = Payment.App()
					// 调用asyncNotify扩展方法，可以为每次API调用，设置独立的异步通知地址
					// 此处设置的异步通知地址的优先级高于全局Config中配置的异步通知地址
					.asyncNotify(payment.getPayNotifyUrl())
					// 设置过期时间
					.optional("time_expire", DateUtils.DF_SEPARATE_T_YMDHM.get().format(DateUtils.getAddorSubtractTimes(invalidTime, 0, 1, 0, 0, 0, 0)))
					// 支付参数
					.pay(subject, outTradeNo, totalAmount);
			LOG.info("-支付宝支付-app支付->{}", JSONTools.obj2json(response));
			// 3. 处理响应或异常
			if (ResponseChecker.success(response)) {
				return response.body;
			} else {
				throw new ProRunTimeException(ErrCode.FAIL.getReturnCode(), "支付宝APP支付调用失败");
			}
		} catch (Exception e) {
			LOG.error("-支付宝支付-app支付-调用遭遇异常，原因：" + e.getMessage());
			throw new ProRunTimeException(ErrCode.FAIL.getReturnCode(), "支付宝APP支付调用失败");
		}
	}

	/**
	 * @作者：陳曉鬆 @时间：2020年8月11日 下午12:04:47 @版本：V1.0 @description：-> 回调验签
	 */
	public static boolean isSign(SysPayment payment, Map<String, String> param) throws ProAffairException {
		if (payment == null) {
			throw new ProRunTimeException(ErrCode.ERR_PARAMETER.getReturnCode(), ErrCode.ERR_PARAMETER.getReturnMsg() + ":支付信息不存在");
		}
		Config config = new Config();
		config.alipayPublicKey = payment.getPayAppKey();
		config.signType = payment.getPaySignType();
		Factory.setOptions(config);
		try {
			return Payment.Common().verifyNotify(param);
		} catch (Exception e) {
			LOG.error("-支付宝支付-app支付-回调验签失败，原因：" + e.getMessage());
			throw new ProRunTimeException(ErrCode.FAIL.getReturnCode(), "支付宝APP支付回调验签失败");
		}
	}

	/**
	 * @作者：陳曉鬆 @时间：2020年8月11日 下午2:56:27 @版本：V1.0 @description：-> 交易退款
	 */
	public static String refund(SysPayment payment, String outTradeNo, BigDecimal price) throws ProAffairException {
		if (payment == null) {
			throw new ProRunTimeException(ErrCode.ERR_PARAMETER.getReturnCode(), ErrCode.ERR_PARAMETER.getReturnMsg() + ":支付信息不存在");
		}
		Config config = getOptions(payment);
		config.alipayPublicKey = payment.getPayAppKey();
		Factory.setOptions(config);
		try {
			AlipayTradeRefundResponse response = Payment.Common().refund(outTradeNo, price.toString());
			LOG.info("-支付宝支付-交易退款->{}->{}", outTradeNo, JSONTools.obj2json(response));
			if (ResponseChecker.success(response)) {
				return response.tradeNo;
			} else {
				throw new ProRunTimeException(ErrCode.FAIL.getReturnCode(), "支付宝APP支付退款失败:" + JSONTools.obj2json(response));
			}
		} catch (Exception e) {
			LOG.error("-支付宝支付-app支付-退款失败，原因：" + e.getMessage());
			throw new ProRunTimeException(ErrCode.FAIL.getReturnCode(), "支付宝APP支付退款失败");
		}
	}

	// public static void main(String[] args) {
	// SysPayment payment = new SysPayment();
	// payment.setPaySignType("RSA2");
	// payment.setPayAppid("2021001188605203");
	// payment.setPayPrivateKey(
	// "MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCFUYivw7JkDU/pNgtoMHFQA0bxR3Za8Iem9zsQ5t5bLelCsi0l9bAWntKzjHz805Yyw7HNzzTiAFS3ULWgIihHbQB88GLCDbGM4yycWA6VLCDMCC8T1JhbG+nr2eZemkJZkPYbgjLGeryvMmOqC5dypnrmcVIt5DxgCu2xc5fD1nPjsFLYgUK/7Q1rfz0v/0A/G5q2Ywk5wOY9u1/tLK3zVzYup2mo9PZyF1AR2B8l04cd9GYUQ5PIvbsyOBEKkr6fiNwCXl9yB0h4iSI1ZoEwRV7fWOpPvBKPPXET41La4d35ETDOmXfLW5im0djuN8dh3UfjLDe/449LooglIwn/AgMBAAECggEAOyCgKKP4mFs3F816XakueDgb3KK/ITIQV8LKlYJvF61TCNuRHobKpB2ogS1Lua31rWoRj5/YamuPJwZKp0y+5H65eq/6fOop1rxiaqy7OvmpShRPHNJrB+1nX8zyWP69co/SNv0Vm+WPjXwhq6ccciLX2yBjPCs/g7EVHmCP7LCqEVeh4Gll4dEHIT+Dh2ODXHyeRpHf2oWQNsYa7fyw7FE+XIDjlpVPLzbWwjATdX7062qefkteVdWkNc2CngAi59MzqAc0zr38vF6D//nTnwjUNUbPQwvA6gqpKVl+YH4S4IjeTpF9WrPhf+dUAvgRDGGMM1XTJKkv9BaSUNDkgQKBgQDAO6u+eLLZOdPX5ZZTtUK2WO/zkXvXtrFRVlvKedrd/5zx2YBsIdiVl2WIqrd8uN7eQ5pw5VkIZlTdoLL8wIYLX/kw/Ettqe2DSIvVKTDsUNitr+R2Szzj93xn73pzz2B/gHjaoRLZOGE8ihcN26TMaP+r8OFHFIjHaimQKklRXwKBgQCxit4Y9mvw+R3wby5BefhITO/lVSHChA1tFzsSAYMJ2A2HBor0g3Tla7ge3swIR6Asij332ktnfeyyRoRsfgZr1krivzx0sohlx/GZ7uY6qIgyKX316Zbx8iQKHGgZPsvnbEjMEBxHIZQsRYTWyLIfqRBn69zuAVS3PapOEffrYQKBgB8RhdBi8YTqM7LRCFq/EOkntqBHAxz6Ce57Zppy10zJ4zOzU24mijqjHWXZMY6W0m5ZvrxAVQNmhpDLSCJRe1ibSksAe7BdpmVxdCgfYCjRaDOqGeKEhnLRrOmfassM2SvCN8YeAk3ZLt3583/p39ipn6jKZZ53UyPnpJAIRZFBAoGAFzmANim+EwazeOlCVsRayzJtS0WopeZaT0PzsTZLavU9R8V+VeAAYaaGrlscu5SLCmiHFK4UoRQi62s4FW0i7+ZXY3P6t5VHLHFMVIOg0FmNf2pYFNwap8myFzSCFZNWXw6WM0OEP3XQCT6K0wHr8yJNiBqdivDXoSTK622ETeECgYAEp7navAbJLYDNuGO3FOER7vESf4fE9saFjUR5oaE2cSQt4STWaMO6NnRZ3GcLwdG1dT2SJbhN+Ihn7BgMGzOjIgnPc6AFYkDIoo+ibf7eHKflkX84HAGiIz5uU9Nq9+113XpCjgHoqYv6Buerb7TTjeigkNSRlA7xxWLM1v7v1A==");
	// payment.setPayPublicKey(
	// "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAr5uv6OTkFFfe/PZJFk37AMV/mgUWw66KPuulaNsZXlNLxcMm88Rz3d47za1Fnf8BpXKbf3QuMEkZLVZ/jcnmM48IDy90rRhXq8UcTibY+4/YdVdnJasXIN9UdEV8peAM3gZSOkPwG+LGSs22HS88eHfPI5+VBZfQ1F+tmKjGhPNES9LrNyAkBHwRf+uGOnQ9ElsoWvZJzoaXJU7G0GRZOzdOnuB2b+8/i7h54R2YxnaiS/ZJi1MXZglWJe4zfshaxKQeUHB9AnPrsu6KLgSea+GTYAO3GS/OppfJF6yt/fAWQYSoHgPdtS+Vfy8a3883Zl8Xq/4kRJ8xFPl71X6gEQIDAQAB");
	// System.out.println(refund(payment, "SY2T20200929142719N00000292", BigDecimal.valueOf(0.01)));
	// }

	private static Config getOptions(SysPayment payment) {
		Config config = new Config();
		config.protocol = "https";
		config.gatewayHost = "openapi.alipay.com";
		config.signType = payment.getPaySignType();
		config.appId = payment.getPayAppid();

		// 为避免私钥随源码泄露，推荐从文件中读取私钥字符串而不是写入源码中
		config.merchantPrivateKey = payment.getPayPrivateKey();

		// 注：证书文件路径支持设置为文件系统中的路径或CLASS_PATH中的路径，优先从文件系统中加载，加载失败后会继续尝试从CLASS_PATH中加载
		// config.merchantCertPath = "<-- 请填写您的应用公钥证书文件路径，例如：/foo/appCertPublicKey_2019051064521003.crt -->";
		// config.alipayCertPath = "<-- 请填写您的支付宝公钥证书文件路径，例如：/foo/alipayCertPublicKey_RSA2.crt -->";
		// config.alipayRootCertPath = "<-- 请填写您的支付宝根证书文件路径，例如：/foo/alipayRootCert.crt -->";

		// 注：如果采用非证书模式，则无需赋值上面的三个证书路径，改为赋值如下的支付宝公钥字符串即可
		config.alipayPublicKey = payment.getPayPublicKey();

		// 可设置异步通知接收服务地址（可选）
		config.notifyUrl = payment.getPayNotifyUrl();

		// 可设置AES密钥，调用AES加解密相关接口时需要（可选）
		// config.encryptKey = "<-- 请填写您的AES密钥，例如：aa4BtZ4tspm2wnXLb1ThQA== -->";
		return config;
	}

}
